use std::{
    fmt::Display,
    ops::{Deref, DerefMut},
    ptr::NonNull,
};

use common_base::{prelude::*, sqlx::mysql::MySqlRow};

use super::rowset::Rowset;

#[derive(Debug, Clone)]
pub struct RowsetOwner(std::pin::Pin<Box<Rowset>>);

impl Default for RowsetOwner {
    fn default() -> Self {
        let mut owner = RowsetOwner(Box::pin(Rowset::default()));
        let owner_ref = (&owner).into();
        owner.set_self_ref(owner_ref);
        owner
    }
}

impl From<Rowset> for RowsetOwner {
    fn from(v: Rowset) -> Self {
        let mut owner = RowsetOwner(Box::pin(v));
        let owner_ref = (&owner).into();
        owner.set_self_ref(owner_ref);
        owner
    }
}

impl TryFrom<MySqlRow> for RowsetOwner {
    type Error = ErrorCode;
    fn try_from(db_row: MySqlRow) -> std::result::Result<Self, Self::Error> {
        Rowset::try_from(db_row).and_then(|v| Ok(v.into()))
    }
}

impl Deref for RowsetOwner {
    type Target = Rowset;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for RowsetOwner {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl Display for RowsetOwner {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

/// serizlize and deserizlize
impl RowsetOwner {
    pub fn deserizlize_from_json(rowset_json: serde_json::Value) -> Result<Self> {
        Rowset::deserizlize_from_json(rowset_json).and_then(|v| Ok(RowsetOwner::from(v)))
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
pub struct RowsetRef(std::ptr::NonNull<RowsetOwner>);

impl RowsetRef {}

impl From<&RowsetOwner> for RowsetRef {
    fn from(v: &RowsetOwner) -> Self {
        RowsetRef(NonNull::from(v))
    }
}
impl From<&mut RowsetOwner> for RowsetRef {
    fn from(v: &mut RowsetOwner) -> Self {
        RowsetRef(NonNull::from(v))
    }
}

impl Deref for RowsetRef {
    type Target = Rowset;

    fn deref(&self) -> &Self::Target {
        unsafe { self.0.as_ref() }
    }
}

impl DerefMut for RowsetRef {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { self.0.as_mut() }
    }
}
